# 简化版多波束数据处理模块
# 核心功能：TIFF读取、按坐标提取点、导入断面线并生成采样点

import numpy as np
from osgeo import gdal
import os
import logging
import math
from config import AppConfig

# 配置日志
logger = logging.getLogger(__name__)

gdal.UseExceptions()

class SimpleMultibeamProcessor:
    """简化版多波束数据处理器
    
    提供三个核心功能：
    1. TIFF文件读取与初始化（过滤缺失值）
    2. 按地理坐标提取高程点
    3. 导入断面线并按指定间隔（默认20米）生成采样点
    """
    def __init__(self, config: AppConfig):
        """初始化简化版多波束数据处理器
        
        Args:
            config: 应用配置对象，用于存储数据
        """
        self.config = config
        
    def load_tiff_file(self, tiff_path: str) -> bool:
        """加载TIFF文件并初始化数据（过滤缺失值）
        
        Args:
            tiff_path: TIFF文件路径
            
        Returns:
            bool: 是否加载成功
        """
        try:
            # 设置缓存以提高性能
            gdal.SetConfigOption('GDAL_CACHEMAX', '512')
            
            # 打开TIFF文件
            dataset = gdal.Open(tiff_path)
            if dataset is None:
                raise Exception(f"无法打开TIFF文件: {tiff_path}")
                
            # 存储基本信息到配置对象
            self.config.tiff_data = dataset.ReadAsArray()
            self.config.tiff_geotransform = dataset.GetGeoTransform()
            
            # 获取NoData值用于后续过滤
            band = dataset.GetRasterBand(1)
            self.config.tiff_no_data_value = band.GetNoDataValue()
            
            logger.info(f"成功加载TIFF文件: {tiff_path}")
            logger.info(f"TIFF尺寸: {dataset.RasterXSize} x {dataset.RasterYSize}")
            
            # 关闭数据集
            dataset = None
            return True
        except Exception as e:
            logger.error(f"加载TIFF文件失败: {str(e)}")
            return False
    
    def get_elevation_at_point(self, x: float, y: float) -> float:
        """根据地理坐标获取TIFF中的高程值（会自动过滤缺失值）
        
        Args:
            x: X坐标（地理坐标）
            y: Y坐标（地理坐标）
            
        Returns:
            float: 高程值，如果点不在TIFF范围内或为缺失值则返回NaN
        """
        try:
            # 检查TIFF数据是否已加载
            if self.config.tiff_data is None or self.config.tiff_geotransform is None:
                raise Exception("请先加载TIFF文件")
            
            # 转换地理坐标到像素坐标
            pixel = (x - self.config.tiff_geotransform[0]) / self.config.tiff_geotransform[1]
            line = (y - self.config.tiff_geotransform[3]) / self.config.tiff_geotransform[5]
            
            # 检查像素坐标是否在TIFF范围内
            if (0 <= pixel < self.config.tiff_data.shape[1] and 
                0 <= line < self.config.tiff_data.shape[0]):
                # 获取整数像素坐标
                pixel_int = int(pixel)
                line_int = int(line)
                
                # 获取高程值
                elevation = self.config.tiff_data[line_int, pixel_int]
                
                # 过滤缺失值
                if (self.config.tiff_no_data_value is not None and 
                    elevation == self.config.tiff_no_data_value):
                    return float('nan')
                
                return elevation
            
            # 点不在范围内返回NaN
            return float('nan')
        except Exception as e:
            logger.warning(f"获取点({x}, {y})的高程值失败: {str(e)}")
            return float('nan')
    
    def import_section_line(self, section_file_path: str, sample_interval: float = 20.0) -> list:
        """导入断面线文件并按指定间隔生成采样点
        
        Args:
            section_file_path: 断面线文件路径（支持CSV或TXT格式）
            sample_interval: 采样间隔（米），默认为20米
            
        Returns:
            list: 包含所有采样点的列表，每个点为字典格式{X, Y, Elevation}
        """
        try:
            # 读取断面线文件
            section_points = self._read_section_file(section_file_path)
            if not section_points:
                raise Exception("未能读取到有效的断面线数据")
            
            # 沿断面线按指定间隔生成采样点
            sample_points = self._generate_sample_points(section_points, sample_interval)
            
            # 为每个采样点提取高程值
            result_points = []
            for point in sample_points:
                x, y = point
                elevation = self.get_elevation_at_point(x, y)
                result_points.append({
                    'X': x,
                    'Y': y,
                    'Elevation': elevation
                })
            
            logger.info(f"成功处理断面线，生成{len(result_points)}个采样点")
            return result_points
        except Exception as e:
            logger.error(f"导入断面线失败: {str(e)}")
            return []
    
    def _read_section_file(self, file_path: str) -> list:
        """读取断面线文件（内部方法）
        
        Args:
            file_path: 断面线文件路径
            
        Returns:
            list: 断面线的坐标点列表[[x1,y1], [x2,y2], ...]
        """
        points = []


        # 读取航线文件(.Lnw)
        if file_path.lower().endswith('.lnw'):
            import re
            pts_regex = re.compile(r'\bPTS\s+(\d+(\.\d+)?)\s+(\d+(\.\d+)?)\b')
            lnn_regex = re.compile(r'\bLNN\s*(\d+)\b')
            eol_regex = re.compile(r'EOL')
            
            curr_lnn = None
            curr_pts = []
            points = []

            with open(file_path, 'r') as f:
                for line in f:
                    pts_match = pts_regex.search(line)
                    if pts_match:
                        x = float(pts_match.group(1))
                        y = float(pts_match.group(3))
                        curr_pts.append([x, y])

                    # 处理LNN分组
                    lnn_match = lnn_regex.search(line)
                    if lnn_match:
                        if curr_lnn is not None:
                            points.extend(curr_pts)
                            curr_pts = []
                        curr_lnn = int(lnn_match.group(1))

                    # 处理EOL结束符
                    if eol_regex.search(line) and curr_lnn is not None:
                        points.extend(curr_pts)
                        curr_pts = []
                        curr_lnn = None

            # 处理最后未结束的分组
            if curr_lnn is not None:
                points.extend(curr_pts)


            # 存储到config配置
            if not hasattr(self.config, 'ship_routes'):
                self.config.ship_routes = {}
            
            if curr_lnn is not None:
                self.config.ship_routes[curr_lnn] = {
                    'points': curr_pts,
                    'length': len(curr_pts),
                    'start_point': curr_pts[0] if curr_pts else None,
                    'end_point': curr_pts[-1] if curr_pts else None
                }

       

       
    def _generate_sample_points(self, section_points: list, sample_interval: float) -> list:
        """沿断面线按指定间隔生成采样点（内部方法）
        
        Args:
            section_points: 断面线的原始点列表
            sample_interval: 采样间隔（米）
            
        Returns:
            list: 生成的采样点列表[[x1,y1], [x2,y2], ...]
        """
        if len(section_points) < 2:
            return section_points.copy()
        
        sample_points = []
        total_length = 0.0
        
        # 计算断面线总长度
        for i in range(1, len(section_points)):
            dx = section_points[i][0] - section_points[i-1][0]
            dy = section_points[i][1] - section_points[i-1][1]
            total_length += math.sqrt(dx*dx + dy*dy)
        
        # 按间隔生成采样点
        current_position = 0.0
        current_segment = 0
        remaining_in_segment = 0.0
        
        while current_position <= total_length:
            # 找到当前位置所在的线段
            while current_segment < len(section_points) - 1:
                dx = section_points[current_segment+1][0] - section_points[current_segment][0]
                dy = section_points[current_segment+1][1] - section_points[current_segment][1]
                segment_length = math.sqrt(dx*dx + dy*dy)
                
                if remaining_in_segment <= 0:
                    remaining_in_segment = segment_length
                    current_segment += 1
                    if current_segment >= len(section_points) - 1:
                        break
                
                if current_position <= current_position + remaining_in_segment:
                    break
                
                current_position += remaining_in_segment
                remaining_in_segment = 0
            
            if current_segment >= len(section_points) - 1:
                break
            
            # 计算采样点坐标
            dx = section_points[current_segment][0] - section_points[current_segment-1][0]
            dy = section_points[current_segment][1] - section_points[current_segment-1][1]
            segment_length = math.sqrt(dx*dx + dy*dy)
            ratio = (segment_length - remaining_in_segment) / segment_length
            
            x = section_points[current_segment-1][0] + ratio * dx
            y = section_points[current_segment-1][1] + ratio * dy
            sample_points.append([x, y])
            
            # 更新位置
            current_position += sample_interval
            remaining_in_segment -= sample_interval
        
        # 添加终点
        if section_points:
            sample_points.append(section_points[-1])
        
        return sample_points